package com.cn.tools;

import java.io.FileInputStream;
import java.sql.*;
import java.util.*;
import javax.sql.*;

//因为这是的使用人数比较的少，所以可以使用静态的变量
public class SqlHelper {
	static Connection ct;
	PreparedStatement ps;
	static ResultSet rs;
	static CallableStatement cs;
	static Properties prop;
	static String driver;
	static String url;
	//使用静态代码块进行初始化，加载实例（其实是使用的反射机制）
	static{
		try {
			//从配置文件中读取配置信息
//			prop = new Properties();
//			prop.load(new FileInputStream("userInfo.properties"));
//			driver = prop.getProperty("driver");
//			url = prop.getProperty("url");
//			Class.forName(driver);
			
			//oracle数据库连接
//			Class.forName("oracle.jdbc.driver.OracleDriver");
//			ct=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","scott","123456")
			
			Class.forName("oracle.jdbc.driver.OracleDriver");
		//	Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//提供一个专门用来得到连接的方法
	public static Connection getConnection(){
		try {
			//ct = DriverManager.getConnection(url);
			ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:XE","erhai","123456");
			//ct = DriverManager.getConnection("jdbc:odbc:mytest");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ct;
	}	
	
	//做分页的时候你是知道表的结构的哦，而变化的就是pageNow和pageCount还有pageSize(有的时候可以让用户来指定)
	//这里也可以显示分页的操作后的数据
	public ArrayList getCountPage(int pageNow,int pageSize){
		ArrayList al = new ArrayList();
		//当你要是另外一些表的时候，这里就需要改动sql语句就可以了，也可以将这sql语句调用Service中去
		//直接当做参数
		String sql = "select top "+pageSize+" * from menu " +
		"where menuid not in" +
		"(select top "+((pageNow-1)*(pageSize))+"  menuid from menu order by menuid)" +
		"order by menuid";
	
//		oracle中的分页
//		--分页查询
//		select * from emp;
//		select a1.*, rownum rn from (select * from emp) a1 ;
//		--输出的是前十条记录
//		select a1.*, rownum rn from (select * from emp) a1 
//		where rownum<=10
//		--输出6-10的记录,这是我们使用rownum rn进行分页查询
//		--如果要查询我们的一部分只需要只要
//		--修改最里面的一部分就可以了
//		--排序也是修改最里面的就可以了order by sal
//		select a2.* from 
//		(select a1.*, rownum rn from 
//		(select * from emp) a1
//		where rownum<=8) a2 where rn >=6
		
		ArrayList<Object> al2 = excuteQuery(sql, null);
		for(int i=0;i<al2.size();i++){
			//System.out.println(rs.getInt(1)+":"+rs.getString(2));
			Object[] obj = (Object[]) al2.get(i);
			al.add(obj);
		}
		return al;
	}
	
//	//获取 总页数
	public int getAllPage(String sql,int pageNow, int pageSize){
		int rowCount = 0;
		try {
			ResultSet rs = excuteQuery2(sql, null);
			rs.next();
			rowCount = rs.getInt(1);//获取了总条数
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			myclose(rs,ps,ct);
		}
		//获取我们的总页数：
		int pageCount = rowCount%pageSize==0?rowCount/pageSize:rowCount/pageSize+1;
		return pageCount;
	}
//	
//	//获取分页技术
//	public ArrayList<User> getUserInfo(int pageNow, int pageSize){
//		ArrayList<User> al =  new ArrayList<User>();
//		int rowCount = getCount(); //获取总的记录数据
//		int pageCount = rowCount%pageSize==0?rowCount/pageSize:rowCount/pageSize+1;
//
//		
//		String sql = "select top "+pageSize+" * from emp " +
//		"where empno not in" +
//		"(select top "+((pageNow-1)*(pageSize))+"  empno from emp order by empno)" +
//		"order by empno";
//
//		ResultSet rs = SqlHelper.excuteQuery2(sql, null);
//		//在将这些数据封装成一个ArrayList集合中去，实现ResutlSet和ArrayList的独立性，有利于释放资源
//		try {
//			while(rs.next()){
//				//将每一条记录封装成一个对象
//				User u = new User();
//				u.setUserId(rs.getInt(1));
//				u.setUsername(rs.getString(2));
//				u.setJob(rs.getString(3));
//				u.setSal(rs.getInt(6));
//				u.setDept(rs.getString(8));
//				//添加到al集合中去
//				al.add(u);
//			}
//		} catch (SQLException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}finally{
//			//SqlHelper.myclose(rs,SqlHelper.getPs(),SqlHelper.getCt());
//			//注意这里，先不要释放资源
//		}
//		return al;
//	}
	
	//适用于oracle数据库的又返值的存储过程(返回游标(需要定义游标))
	public static void callPro2(String sql,String[] paras,String[] out){
		try{
			ct = getConnection();
			//问号赋值
			cs = ct.prepareCall(sql);
			if(paras!=null){
				for(int i=0;i<paras.length;i++){
					cs.setObject(i+1, paras[i]);
				}
			}
			//给out参数赋值
			if(out!=null){
				for(int i=0;i<out.length;i++){
					cs.registerOutParameter(paras.length+1+i, Integer.parseInt(out[i].toString()));
				}
			}
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}finally{
			//暂时先不要关闭,调用者可能要使用
		}
	}
	//这里可能使用与oracle的存储过程
	//调用存储过程，形式可能是这样的：{call 过程(?,?,?,?)}，这是没有返回值的存储过程
	public static void callPro(String sql, String[] paras){
		try{
			ct = getConnection();
			//问号赋值
			if(paras!=null){
				for(int i=0;i<paras.length;i++){
					cs.setObject(i+1, paras[i]);
				}
			}
			//执行操作
			cs.execute();
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);
		}finally{
			myclose(rs,cs,ct);
		}
	}
	
	//完成了初始化的任务，我们要开始为这个类提供一些CURD的方法(这只是传多个sql语句过来的方法)
	public void excuteUpdate2(String sql[], String[][] paras){
		//先得到连接
		ct = getConnection();
		//开始创建ps
		try {	
			ct.setAutoCommit(false);
			//开始为参数进行赋值
			for(int i=0;sql!=null&&i<sql.length;i++){
				//创建一个ps
				ps = ct.prepareStatement(sql[i]);
				for(int j=0;j<paras[i].length;j++){
					ps.setObject(j+1,paras[i][j]);
				}
				//然后在去执行
				//执行个更新个的操作
				ps.executeUpdate();
			}
			//在这里设置一个提交事物
			ct.commit();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			try {
				ct.rollback();//设置回滚动作
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
			//开发中要抛出运行时异常
			throw new RuntimeException(e.getMessage());
		}finally{
			//关闭资源
			myclose(rs,ps,ct);
		}
	}
	//完成了初始化的任务，我们要开始为这个类提供一些CURD的方法(这只是传了一个sql语句过来的方法)
	public boolean excuteUpdate(String sql, String[] paras){
		boolean flag = true;
		//先得到连接
		ct = getConnection();
		//开始创建ps
		try {
			ps = ct.prepareStatement(sql);
			//开始为参数进行赋值
			for(int i=0;paras!=null&&i<paras.length;i++){
				ps.setObject(i+1, paras[i]);
			}
			//然后在去执行
			ps.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			flag = false;
			e.printStackTrace();
			//开发中要抛出运行时异常
			throw new RuntimeException(e.getMessage());
		}finally{
			//关闭资源
			myclose(rs,ps,ct);
		}
		return flag;
	}
	
	//查询结果集
	//返回List集合就是可以实现ResultSet独立的关闭，实现代码的封装性
	public ArrayList excuteQuery(String sql, String[] paras){
		ct = getConnection();
		ArrayList alList=null;
		try{
			ps = ct.prepareStatement(sql);
			for(int i=0;paras!=null&&i<paras.length; i++){
				ps.setString(i+1, paras[i]);
			}
			rs = ps.executeQuery();
			alList = new ArrayList();//用来记住查询返回的结果
			//开始进行封装成一个ArrayList集合
			ResultSetMetaData rmd = rs.getMetaData();
			int total_col = rmd.getColumnCount();
			
			while(rs.next()){
				Object[] obj = new Object[total_col];//这条语句用来封装很多我们的一行记录
				for(int i=1; i<=total_col; i++){
					obj[i-1] = rs.getObject(i);
				}
				alList.add(obj);
			}	
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);
		}finally{
			myclose(rs,ps,ct);
		}
		return alList;
	}
	
	public ResultSet excuteQuery2(String sql, String[] paras){
		ct = getConnection();
		try{
			ps = ct.prepareStatement(sql);
			for(int i=0;paras!=null&&i<paras.length; i++){
				ps.setString(i+1, paras[i]);
			}
			rs = ps.executeQuery();	
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);
		}finally{
			//先不能关闭
			//myclose(rs,ps,ct);
		}
		return rs;
	}
	//关闭我们的资源
	public static void myclose(ResultSet rs,Statement ps, Connection ct){
		try{
			if(rs!=null){
				rs.close();
			}
			if(ps!=null){
				ps.close();
			}
			if(ct!=null){
				ct.close();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}

}
